package com.ruoyi.quartz.task;

import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.IotConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.UserStatus;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.es.domain.EsDeviceDataInfo;
import com.ruoyi.es.domain.EsDeviceInfo;
import com.ruoyi.es.domain.EsValueInfo;
import com.ruoyi.es.mapper.EsDeviceInfoMapper;
import com.ruoyi.system.cache.AlarmConfigCache;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.Forest.ExtendDict;
import com.ruoyi.system.domain.Forest.IotDeviceInfo;
import com.ruoyi.system.domain.Forest.IotResult;
import com.ruoyi.system.domain.Forest.grm.AuthGRM;
import com.ruoyi.system.domain.Forest.grm.GRMData;
import com.ruoyi.system.domain.Forest.second.*;
import com.ruoyi.system.domain.cache.DeviceCache;
import com.ruoyi.system.domain.cache.GatewayCache;
import com.ruoyi.system.service.*;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.nutz.el.El;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.ruoyi.common.utils.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.nutz.lang.Lang;
import org.nutz.lang.util.Context;
/**
 * 定时任务调度测试
 * 
 * @author ruoyi
 */
@Component("ryTask")
public class RyTask
{
    private static final Logger log = LoggerFactory.getLogger(RyTask.class);
    @Autowired
    private ISysDeviceService sysDeviceService;

    @Autowired
    private ISysConfigService sysConfigService;

//    @Resource
//    private DeviceAsyncClient deviceAsyncClient;

    @Resource
    private SecondDeviceAsyncClient secondDeviceAsyncClient;

    @Autowired
    private ISysAlarmService sysAlarmService;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private AlarmConfigCache alarmConfigCache;

    @Autowired
    private ISysDataBoardService sysDataBoardService;
    @Resource
    private GRMLoadDataClient grmLoadDataClient;

    @Resource
    private GRMAuthClient grmAuthClient;

    @Autowired
    private ISysHeatFeeTemplateService sysHeatFeeTemplateService;

    @Autowired
    private ISysHeatFeeService sysHeatFeeService;


    public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i)
    {
        System.out.println(StringUtils.format("执行多参方法： 字符串类型{}，布尔类型{}，长整型{}，浮点型{}，整形{}", s, b, l, d, i));
    }

    public void ryParams(String params)
    {
        System.out.println("执行有参方法：" + params);
    }

    public void ryNoParams()
    {
        System.out.println("执行无参方法");
    }


    //重置计费时间
    public void restHeatDate(Long deptId){
        Date now = DateUtils.getNowDate();
        String date = DateUtils.parseDateToStr("MM-dd", now);
        //开始重置热费
        if (sysConfigService.selectConfigByKey("sys.rest.heatDate").equals(date)){
            //获取年份
            String year = DateUtils.dateTime(now).substring(0,4);
            SysConfig yearConfig = sysConfigService.selectConfigById(9L);
            yearConfig.setConfigValue(year);
            yearConfig.setUpdateBy("system");
            yearConfig.setRemark("系统自动重置");
            yearConfig.setUpdateTime(now);
            sysConfigService.updateConfig(yearConfig);

            SysDevice sysDevice = SysDevice.builder()
                    .queryConfig("2")
                    .buildingId(-1L)
                    .deviceStatus(UserStatus.OK.getCode())
                    .delFlag(UserStatus.OK.getCode())
                    .deviceType(IotConstants.DEVICE_TYPE_HEATING)
                    .deptId(deptId)
                    .build();
            List<SysDevice> devices = sysDeviceService.selectSysDeviceList(sysDevice);

            //查询出当前部门下的所有热费
            SysHeatFeeTemplate sysHeatFeeTemplate = new SysHeatFeeTemplate();
            sysHeatFeeTemplate.setDeptId(deptId);
            Map <Long,SysHeatFeeTemplate> sysHeatFeeTemplateMap =  sysHeatFeeTemplateService.selectSysHeatFeeTemplateList(sysHeatFeeTemplate).stream().collect(Collectors.toMap(SysHeatFeeTemplate ::getTemplateId, Function.identity()));
            devices.forEach(device -> {
                if (device.getHeatFeeId() == null) {

                } else {
                    //获取缓存热量
                    DeviceCache deviceCache = redisCache.getCacheObject(CacheConstants.IOT_DEVICE + device.getDeviceCode());
                    BigDecimal heatQuantity ;
                    if (deviceCache == null || deviceCache.getHeatQuantity() == null){
                        heatQuantity = new BigDecimal("0");
                    }else {
                        heatQuantity = BigDecimal.valueOf(deviceCache.getHeatQuantity());
                    }
                    //查询设备对应的热费信息
                    SysHeatFeeTemplate template = sysHeatFeeTemplateMap.get(device.getHeatFeeId());

                    createBeginHeatFee(device, heatQuantity, template);
                }
            });
        }

    }

    //统计热费
    public void statisticsHeatFee(Long deptId){
        Date now = DateUtils.getNowDate();
        //获取年份
        String year = sysConfigService.selectConfigByKey("sys.heat.year");
        //结束时间
        String end = sysConfigService.selectConfigByKey("sys.end.heatDate");
        Date endDate = DateUtils.parseDate((Integer.parseInt(year) + 1) + "-" + end);
        if ( now.after(endDate)){
            return;
        }

        SysDevice sysDevice = SysDevice.builder()
                .queryConfig("2")
                .buildingId(-1L)
                .deviceStatus(UserStatus.OK.getCode())
                .delFlag(UserStatus.OK.getCode())
                .deviceType(IotConstants.DEVICE_TYPE_HEATING)
                .deptId(deptId)
                .deviceId(6117L)
                .build();
        List<SysDevice> devices = sysDeviceService.selectSysDeviceList(sysDevice);

        //查询出当前部门下的所有热费
        SysHeatFeeTemplate sysHeatFeeTemplate = new SysHeatFeeTemplate();
        sysHeatFeeTemplate.setDeptId(deptId);
        Map <Long,SysHeatFeeTemplate> sysHeatFeeTemplateMap =  sysHeatFeeTemplateService.selectSysHeatFeeTemplateList(sysHeatFeeTemplate).stream().collect(Collectors.toMap(SysHeatFeeTemplate ::getTemplateId, Function.identity()));
        devices.forEach(device -> {
            if (device.getHeatFeeId() == null) {

            } else {
                //获取缓存热量
                DeviceCache deviceCache = redisCache.getCacheObject(CacheConstants.IOT_DEVICE + device.getDeviceCode());
                BigDecimal heatQuantity ;
                if (deviceCache == null || deviceCache.getHeatQuantity() == null){
                    heatQuantity = new BigDecimal("0");
                }else {
                    heatQuantity = BigDecimal.valueOf(deviceCache.getHeatQuantity());
                }
                //查询设备对应的热费信息
                SysHeatFeeTemplate template = sysHeatFeeTemplateMap.get(device.getHeatFeeId());

                //上一次消费记录
                SysHeatFee lastHeatFee = sysHeatFeeService.selectLastSysHeatFeeByDeviceId(device.getDeviceId());

                //如果不存在，则插入一条初始化数据，当日热费为0，记录上次热量
                if (lastHeatFee == null) {

                    createBeginHeatFee(device, heatQuantity, template);
                }
                //如果存在，统计热费
                else {

                    if (template != null){
                        BigDecimal currentHeatFee;
                        Context context = Lang.context();
                        context.set("area", device.getArea());
                        context.set("price",device.getPrice());
                        context.set("heat",heatQuantity.subtract(lastHeatFee.getLastHeatQuantity()));
                        context.set("heatPrice", device.getHeatPrice());
                        context.set("totalHeat", heatQuantity.subtract(lastHeatFee.getBeginHeatQuantity()));

                        //查询热费表数据 一档
                        if (template.getTargetType() == 1){
                            El exp = new El(template.getExpressionFirst());
                            currentHeatFee = new BigDecimal(String.valueOf(exp.eval(context)));
                        }
                        //多档
                        else {
                            if ((Boolean) new El(template.getFirstTarget()).eval(context)) {
                                El exp = new El(template.getExpressionFirst());
                                currentHeatFee = new BigDecimal(String.valueOf(exp.eval(context)));
                            }else if ((Boolean) new El(template.getSecondTarget()).eval(context)) {
                                El exp = new El(template.getExpressionSecond());
                                currentHeatFee = new BigDecimal(String.valueOf(exp.eval(context)));
                            }else {
                                El exp = new El(template.getExpressionThird());
                                currentHeatFee = new BigDecimal(String.valueOf(exp.eval(context)));
                            }
                        }
                        SysHeatFee heatFee = new SysHeatFee();
                        heatFee.setDeviceId(device.getDeviceId());
                        heatFee.setDeptId(device.getDeptId());
                        heatFee.setFee(currentHeatFee.subtract(lastHeatFee.getBeginFee()));
                        heatFee.setLastHeatQuantity(heatQuantity);
                        heatFee.setInDate(DateUtils.getNowDate());
                        heatFee.setBeginHeatQuantity(lastHeatFee.getBeginHeatQuantity());//初始值
                        heatFee.setBeginFee(lastHeatFee.getBeginFee());
                        sysHeatFeeService.insertSysHeatFee(heatFee);
                    }
                }
            }
        });
    }


    ///创建初始化数据
    private void createBeginHeatFee(SysDevice device, BigDecimal heatQuantity, SysHeatFeeTemplate template) {
        Context context = Lang.context();
        context.set("area", device.getArea());
        context.set("price",device.getPrice());
        context.set("heat", 0);
        context.set("heatPrice", device.getHeatPrice());
        context.set("totalHeat", 0);
        El exp = new El(template.getExpressionFirst());
        SysHeatFee heatFee = new SysHeatFee();
        heatFee.setDeviceId(device.getDeviceId());
        heatFee.setDeptId(device.getDeptId());
        heatFee.setFee(new BigDecimal(String.valueOf(exp.eval(context))));
        heatFee.setLastHeatQuantity(heatQuantity);
        heatFee.setInDate(DateUtils.getNowDate());
        heatFee.setBeginHeatQuantity(heatQuantity);
        heatFee.setBeginFee(heatFee.getFee());
        sysHeatFeeService.insertSysHeatFee(heatFee);
    }

    //统计数据
    public void statistics(Long deptId){
        //统计时间
        Date date = DateUtils.getNowDate();
        String expressDate = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.addDays(date, 25));
        //查询出所有阀门
        SysDevice sysDevice = SysDevice.builder()
                .queryConfig("1")
                .buildingId(-1L)
                .deviceStatus(UserStatus.OK.getCode())
                .delFlag(UserStatus.OK.getCode())
                .deviceType(IotConstants.DEVICE_TYPE_VALVE)
                .deptId(deptId)
                .isTest("1")
                .build();
        //分页查询  每页50条
        List<SysDevice> devices = sysDeviceService.selectSysDeviceList(sysDevice);
        //设备code和设备对象映射
        Map<String, SysDevice> deviceMap = devices.stream().collect(Collectors.toMap(SysDevice::getDeviceCode, Function.identity()));
        //每次遍历50个设备
        // 每批次的大小
        int batchSize = 50;

        BigDecimal totalTemperature = new BigDecimal("0");

        // 遍历列表，每次处理固定数量的数据
        for (int i = 0; i < devices.size(); i += batchSize) {
            // 创建一个新的列表来存放每批数据
            List<String> batchList = new ArrayList<>();

            // 确定当前批次的实际大小（可能是少于或等于batchSize）
            int toIndex = Math.min(i + batchSize, devices.size());

            // 将元素从originalList复制到batchList
            for (int j = i; j < toIndex; j++) {
                batchList.add(devices.get(j).getDeviceCode());
            }

            // 对每批次的数据进行操作
            BaseResult<List<ValueResult>> result = secondDeviceAsyncClient.readStatusSync(batchList);
            if (result.getCode() == 200){
                List<ValueResult> data = result.getData();
                BigDecimal t = data.stream().map(ValueResult::getTempIndoor).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);

                data.forEach(valueResult -> {
                    DeviceCache deviceCache = redisCache.getCacheObject(CacheConstants.IOT_DEVICE + valueResult.getNodeId());
                    if (deviceCache == null){
                        deviceCache = new DeviceCache();
                    }
                    EsValueInfo logInfo = new EsValueInfo();
                    SysDevice deviceInfo = deviceMap.get(valueResult.getNodeId());
                    if (deviceInfo != null) {
                        BeanUtils.copyProperties(valueResult, logInfo);
                        logInfo.setDeptId(deptId);
                        logInfo.setDeviceId(deviceInfo.getDeviceId());
                        logInfo.setDeviceCode(deviceInfo.getDeviceCode());
                        logInfo.setCreateTime(date);
                        logInfo.setTimestamp(date.getTime());
                        sysDeviceService.logValueInfo(logInfo, String.valueOf(deptId));
                    } else {
                        //发送设备报警
//                      sysAlarmService.insertDeviceAlarm(device);
                    }
                    //更新网关缓存信息
                    GatewayCache gatewayCache = redisCache.getCacheObject(CacheConstants.IOT_GATEWAY + deviceInfo.getGatewayId());
                    if (gatewayCache == null){
                        gatewayCache = new GatewayCache();
                    }
                    gatewayCache.update(valueResult);
                    redisCache.setCacheObject(CacheConstants.IOT_GATEWAY + deviceInfo.getGatewayId(), gatewayCache);

                    //更新开关阀状态
                    sysDeviceService.updateDeviceStatus(deviceCache, valueResult);
                    deviceCache.update(valueResult);
                    //如果是关阀状态
                    if (deviceCache.getWorkMode() != null && deviceCache.getWorkMode().equals(IotConstants.SET_MODE_IOT_FLOW) && deviceCache.getValveOpening() == 0){
                        //最近三日内产生热费数大于两条，则认为数据有异常
                        int count = sysHeatFeeService.checkFeeChange(valueResult.getNodeId());
                        if (count >= 2){
                            SysDevice device = sysDeviceService.selectSysDeviceByDeviceCode(valueResult.getNodeId(), deptId);
                            sysAlarmService.insertCloseAlarm(device);
                        }
                    }
//                    //自动开关阀
//                    if (valueResult.getTempSet().compareTo(valueResult.getTempIndoor()) > 0){//开阀
//                        secondDeviceAsyncClient.setOpening(new Date().getTime(), valueResult.getNodeId(), 85, expressDate);
//                    } else if(valueResult.getTempSet().compareTo(valueResult.getTempIndoor()) < 0){//关阀
//                        secondDeviceAsyncClient.setOpening(new Date().getTime(), valueResult.getNodeId(), 15, expressDate);
//                    }
                    redisCache.setCacheObject(CacheConstants.IOT_DEVICE + valueResult.getNodeId(), deviceCache);
                });
                totalTemperature = totalTemperature.add(t);
            }
        }
        SysDataBoard sysDataBoard = new SysDataBoard();
//        if (redisCache.getCacheObject(CacheConstants.GRM_TOKEN_URL) == null) {
//            AuthGRM authGRM = grmAuthClient.getToken();
//            if (authGRM.getCode() == 0) {
//                redisCache.setCacheObject(CacheConstants.GRM_TOKEN_URL, "http://" + authGRM.getAddr() + "/exdata?SID=" + authGRM.getSid() + "&OP=R");
//                grmLoadDataClient.getData();
//            }
//        }
//        GRMData grmData = grmLoadDataClient.refreshData();
//        if (grmData.getCode() == 1){
//            redisCache.setCacheObject(CacheConstants.GRM_TOKEN_URL, null);
//            sysDataBoard.setTemparatureOut(new BigDecimal("-99"));
//        }else {
//            sysDataBoard.setTemparatureOut(new BigDecimal(grmData.getTemperature()));
//        }
        GRMData grmData = sysDataBoardService.loadPlcData(deptId);
        if (grmData.getCode() == 1) {
            grmData = sysDataBoardService.loadPlcData(deptId);
        }
        if (grmData.getCode() == 1){
            sysDataBoard.setTemparatureOut(new BigDecimal("-99"));
        } else {
            sysDataBoard.setTemparatureOut(new BigDecimal(grmData.getTemperature()));
        }
        sysDataBoard.setDeptId(deptId);
        sysDataBoard.setInDate(date);
        if (devices.isEmpty()){
            sysDataBoard.setTemparatureIn(new BigDecimal("0"));
        }else {
            sysDataBoard.setTemparatureIn(totalTemperature.divide(new BigDecimal(devices.size()), 2, RoundingMode.HALF_UP));
        }
        //供热功率
        BigDecimal total = BigDecimal.valueOf(sysDeviceService.selectDeviceInfoAgg(deptId, "heatPower"));
        //总面积
        BigDecimal area = sysDeviceService.selectArea(deptId);
        sysDataBoard.setHeatPower(total.multiply(new BigDecimal("1000")).divide(area, 2, RoundingMode.HALF_UP));
        sysDataBoardService.insertSysDataBoard(sysDataBoard);
    }
    //定时同步设备数据
    public void syncDevice(Long deptId, String collectCycle){
        Date date = new Date();
        SysDevice sysDevice = SysDevice.builder()
                                        .queryConfig("1")
                                        .buildingId(-1L)
                                        .deviceStatus(UserStatus.OK.getCode())
                                        .delFlag(UserStatus.OK.getCode())
                                        .deviceType(IotConstants.DEVICE_TYPE_HEATING)
                                        .deptId(deptId)
//                                        .collectCycle(collectCycle)
                                        .build();
        List<SysDevice> devices = sysDeviceService.selectSysDeviceList(sysDevice);
        devices.forEach(device -> {
            BaseResult<PageResult<DeviceDataResult>> result = secondDeviceAsyncClient.getDeviceData(device.getDeviceCode());
            if (result.getCode() == 200){
                PageResult<DeviceDataResult> data = result.getData();
                if (!data.getItems().isEmpty()){

                    DeviceCache deviceCache = redisCache.getCacheObject(CacheConstants.IOT_DEVICE + device.getDeviceCode());
                    if (deviceCache == null){
                        deviceCache = new DeviceCache();
                        deviceCache.setTimeUpload(new Date(0));
                    }
                    DeviceDataResult deviceDataResult = data.getItems().get(0);
                    if (deviceCache.getTimeUpload().equals(deviceDataResult.getTimeUpload())){
                        log.info("设备数据未更新，跳过");
                    } else {
                        EsDeviceDataInfo logInfo = new EsDeviceDataInfo();
                        BeanUtils.copyProperties(deviceDataResult, logInfo);
                        logInfo.setDeptId(deptId);
                        logInfo.setDeviceId(device.getDeviceId());
                        logInfo.setDeviceCode(device.getDeviceCode());
                        logInfo.setCreateTime(date);
                        logInfo.setTimestamp(date.getTime());
                        //记录历史数据
                        sysDeviceService.secondLogDeviceInfo(logInfo, String.valueOf(deptId));
                        if (device.getAlarmConfigId() != null) {
                            SysAlarmConfig alarmConfig= alarmConfigCache.getAlarmConfig(device.getAlarmConfigId());
                            if (alarmConfig != null) {
                                Context context = Lang.context();
                                context.set("iot", deviceDataResult);
                                //触发告警
                                if ((Boolean) El.eval(context, alarmConfig.getAlarmExpression())){
                                    sysAlarmService.insertSecondDeviceIotAlarm(deviceDataResult, device);
                                }
                            }
                        }

                        deviceCache.update(deviceDataResult);
                        redisCache.setCacheObject(CacheConstants.IOT_DEVICE + device.getDeviceCode(), deviceCache);
                    }

                }else {
                  //发送设备报警
//                  sysAlarmService.insertDeviceAlarm(device);
                }
            }else {
                //发送设备报警
//                sysAlarmService.insertDeviceAlarm(device);
            }
        });
//            IotResult<ExtendDict<IotDeviceInfo>> result = deviceAsyncClient.getDeviceInfo(device.getDeviceCode());
//            if (result.getCode() == 0){
//                IotDeviceInfo iotDeviceInfo = result.getData().getExtendDict();
//
//                EsDeviceInfo logInfo = new EsDeviceInfo();
//                BeanUtils.copyProperties(iotDeviceInfo, logInfo);
//                logInfo.setDeptId(deptId);
//                logInfo.setDeviceId(device.getDeviceId());
//                logInfo.setDeviceCode(device.getDeviceCode());
//                logInfo.setCreateTime(date);
//                if (iotDeviceInfo.getDeviceClock() == null){
//                    logInfo.setDeviceClock(date);
//                }else {
//                    logInfo.setDeviceClock(iotDeviceInfo.getDeviceClock());
//                }
//                //记录历史数据
//                sysDeviceService.logDeviceInfo(logInfo, String.valueOf(deptId));
//
//                SysAlarmConfig alarmConfig= alarmConfigCache.getAlarmConfig(device.getAlarmConfigId());
//                Context context = Lang.context();
//                context.set("iot", iotDeviceInfo);
//                //触发告警
//                if ((Boolean) El.eval(context, alarmConfig.getAlarmExpression())){
//                    sysAlarmService.insertDeviceIotAlarm(iotDeviceInfo, device);
//                }
//            } else {
//                //发送设备报警
//                sysAlarmService.insertDeviceAlarm(device);
//            }

    }


    //mock数据
    public void mockData(Long deptId){
        Date date = new Date();
        SysDevice sysDevice = SysDevice.builder()
                .deviceStatus(UserStatus.OK.getCode())
                .delFlag(UserStatus.OK.getCode())
                .deviceType(IotConstants.DEVICE_TYPE_HEATING)
                .deptId(deptId)
                .build();
        List<SysDevice> devices = sysDeviceService.selectSysDeviceList(sysDevice);
        devices.forEach(device -> {
            DeviceDataResult deviceDataResult = new DeviceDataResult();
            deviceDataResult.random(device.getDeviceId() + "");
            EsDeviceDataInfo logInfo = new EsDeviceDataInfo();
            BeanUtils.copyProperties(deviceDataResult, logInfo);
            logInfo.setDeptId(deptId);
            logInfo.setDeviceId(device.getDeviceId());
            logInfo.setDeviceCode(device.getDeviceCode());
            logInfo.setCreateTime(date);
            logInfo.setTimestamp(date.getTime());
            //记录历史数据
            sysDeviceService.secondLogDeviceInfo(logInfo, String.valueOf(deptId));
            if (device.getAlarmConfigId() != null) {
                SysAlarmConfig alarmConfig= alarmConfigCache.getAlarmConfig(device.getAlarmConfigId());
                if (alarmConfig != null) {
                    Context context = Lang.context();
                    context.set("iot", deviceDataResult);
                    //触发告警
                    if ((Boolean) El.eval(context, alarmConfig.getAlarmExpression())){
                        sysAlarmService.insertSecondDeviceIotAlarm(deviceDataResult, device);
                    }
                }
            }
        });
//        输出执行时间
        log.info("执行时间：" + (System.currentTimeMillis() - date.getTime()));
    }



}
